<template>
    <div class="material-select">
        <popup
            ref="popupRef"
            width="830px"
            custom-class="body-padding"
            :title="`选择${tipsText}`"
            @confirm="handleConfirm"
            @close="handleClose"
        >
            
            <template v-if="!props.hiddenUpload" v-slot:trigger>
                
                <div class="clearfix" @click.stop>
                    <draggable class="draggable" v-model="fileList" animation="300" item-key="id">
                        <template v-slot:item="{ element, index }">
                            <div
                                class="material-preview"
                                :class="{
                                    'is-disabled': disabled,
                                    'is-one': limit == 1
                                }"
                                @click="showPopup(index)"
                            >
                                
                                <del-wrap @close="deleteImg(index)">
                                    <file-item
                                        :uri="excludeDomain ? getImageUrl(element) : element"
                                        :file-size="size"
                                        :type="type"
                                    ></file-item>
                                </del-wrap>
                                <div class="operation-btns text-xs text-center">
                                    <span>修改</span>
                                    |
                                    <span @click.stop="handlePreview(element)">查看</span>
                                </div>
                            </div>
                        </template>
                    </draggable>
                    
                    
                    <div
                        class="material-upload"
                        @click="showPopup(-1)"
                        v-show="showUpload"
                        :class="{
                            'is-disabled': disabled,
                            'is-one': limit === 1,
                            [uploadClass]: true
                        }"
                    >
                        <slot name="upload">
                            <div
                                class="upload-btn"
                                :style="{
                                    width: size,
                                    height: size
                                }"
                            >
                                <icon :size="25" name="el-icon-Plus"/>
                                <span>添加</span>
                            </div>
                        </slot>
                    </div>
                
                
                </div>
            </template>
            
            
            <template v-slot:default>
                <el-scrollbar>
                    <div class="material-wrap">
                        <material
                            ref="materialRef"
                            :type="props.type"
                            :file-size="props.fileSize"
                            :limit="materialLimit"
                            @change="selectChange"
                        />
                    </div>
                </el-scrollbar>
            </template>
        </popup>
        <preview v-model="showPreview" :url="previewUrl" :type="type"/>
    </div>
</template>

<script lang="ts" setup>
import Draggable from 'vuedraggable'
import Popup from '@/components/popup/index.vue'
import Material from './index.vue'
import Preview from './preview.vue'
import {useThrottleFn} from '@vueuse/shared'
import useAppStore from "@/base/stores/modules/app";
import {ComputedRef} from "vue";


interface PickerProps {
    modelValue?: string | any [],
    type?: string,
    size?: string,
    fileSize?: string,
    limit?: number,
    disabled?: boolean,
    hiddenUpload?: boolean,
    uploadClass?: string,
    excludeDomain?: boolean
}

const props = withDefaults(defineProps<PickerProps>(), {
    modelValue: () => [],
    // 文件类型
    type: 'image',
    // 选择器尺寸
    size: '100px',
    // 文件尺寸
    fileSize: '100px',
    // 选择数量限制
    limit: 1,
    // 禁用选择
    disabled: false,
    // 隐藏上传框*(目前在富文本中使用到)
    hiddenUpload: false,
    uploadClass: '',
    //选择的url排出域名
    excludeDomain: false
})

const {disabled, limit, modelValue} = toRefs(props)

// 定义传入文件集合
const fileList = ref<any[]>([])

// 定义已选择参数
const select = ref<any[]>([])

/**
 * 选择文本
 */
const tipsText = computed(() => {
    switch (props.type) {
        case 'image':
            return '图片'
        case 'video':
            return '视频'
        default:
            return ''
    }
})


/**
 * 监听传入的url
 */
watch(
    modelValue,
    (val: any[] | string) => {
        fileList.value = Array.isArray(val) ? val : val == '' ? [] : [val]
    },
    {
        immediate: true
    }
)


/**
 * 子图片选择参数
 *
 * @param val
 */
function selectChange(val: any[]) {
    select.value = val
}


/**
 * 计算图片limit
 */
const materialLimit = computed<number>(() => {
    if (!isAdd.value) {
        return 1
    }
    
    if (limit.value == -1) {
        return 20
    }
    
    return limit.value - fileList.value.length
})


/**
 * 确定使用节流阀
 */
const handleConfirm = useThrottleFn(
    () => {
        const selectUri = select.value.map((item) =>
            props.excludeDomain ? item.path : item.uri
        )
        
        if (!isAdd.value) {
            fileList.value.splice(currentIndex.value, 1, selectUri.shift())
        } else {
            fileList.value = [...fileList.value, ...selectUri]
        }
        
        handleChange()
    },
    1000,
)

/**
 * 定义事件处理
 */

const emit = defineEmits(['change', 'update:modelValue'])

function handleChange() {
    const valueImg = limit.value != 1 ? fileList.value : fileList.value[0] || ''
    
    emit('update:modelValue', valueImg)
    emit('change', valueImg)
    handleClose()
}

/**
 * 取消
 */
function handleClose() {
    nextTick(() => {
        if (props.hiddenUpload) fileList.value = []
        materialRef.value?.clearSelect()
    })
}


const popupRef = ref<InstanceType<typeof Popup>>()
const materialRef = ref<InstanceType<typeof Material>>()
const previewUrl = ref('')
const showPreview = ref(false)


const isAdd = ref(true)
const currentIndex = ref(-1)


const {getImageUrl} = useAppStore()


provide('limit', props.limit)
provide('hiddenUpload', props.hiddenUpload)


const showUpload = computed(() => {
    return props.limit - fileList.value.length > 0
})


/**
 * 删除当前图片
 *
 * @param index
 */
function deleteImg(index: number) {
    fileList.value.splice(index, 1)
    handleChange()
}


/**
 * 显示图片
 *
 * @param url
 */
const handlePreview = (url: string) => {
    previewUrl.value = url
    showPreview.value = true
}


/**
 * 弹窗
 * @param index
 */
function showPopup  (index: number)  {
    if (disabled.value) return
    if (index >= 0) {
        isAdd.value = false
        currentIndex.value = index
    } else {
        isAdd.value = true
    }
    popupRef.value?.open()
}

</script>

<style scoped lang="scss">
.material-select {
    .material-upload,
    .material-preview {
        position: relative;
        border-radius: 4px;
        cursor: pointer;
        margin-right: 8px;
        margin-bottom: 8px;
        box-sizing: border-box;
        float: left;
        
        &.is-disabled {
            cursor: not-allowed;
        }
        
        &.is-one {
            margin-bottom: 0;
        }
        
        &:hover {
            .operation-btns {
                display: block;
            }
        }
        
        .operation-btns {
            display: none;
            position: absolute;
            bottom: 0;
            border-radius: 4px;
            width: 100%;
            line-height: 2;
            color: #fff;
            background-color: rgba(0, 0, 0, 0.3);
        }
    }
    
    .material-upload {
        :deep(.upload-btn) {
            @apply text-tx-secondary box-border rounded border-br border-dashed border flex flex-col justify-center items-center;
        }
    }
}

.material-wrap {
    min-width: 720px;
    height: 430px;
    @apply border-t border-b border-br;
}
</style>
